/*
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "msPhysicalInterface.h"

namespace atomism{

namespace csts
{
 double h	=	6.6260755e-34;   	// J S
 double hb	=	1.054571628e-34; 
 double kb	=	1.380658e-23;		// J/mol/K
 double pi	=	3.14159265;
 double R	=	8.3144621; 		// J/mol
 double Nav	=	6.0221413e23;
 }

using namespace std;

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

bool msPhysicalInterface::isInterfaceRegisteredInPython=0;
msRegistrar msPhysicalInterface::Registrar("msPhysicalInterface", msPhysicalInterface::createInstance);
 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

std::ostream& operator<<(std::ostream& out,const msPhysicalInterface& inter)
{
 return( inter.print(out) );
 }

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void msPhysicalInterface::registryInPython() {
  
 #if USE_PYTHON
 msTreeMapper::registryInPython();
 if( ! msPhysicalInterface::isInterfaceRegisteredInPython ) {
   
     using namespace boost::python;
     class_<msPhysicalInterface,bases<msTreeMapper >
           ,boost::shared_ptr<msPhysicalInterface> >
         ("msPhysicalInterface",
	  "Defines a physical object: provides the management of units + parameters + output ",
	   no_init)
    .def( "New", &msPhysicalInterface::New , "Create a new object")
    .staticmethod("New")
    .def( "getUnits", &msPhysicalInterface::getUnits ,
	  "return a shared pointer to the units manager" )
    .def( "getParameters",&msPhysicalInterface::getParameters ,
	  "return a shared pointer to the parameters manager" )
    .def( "setUnits", &msPhysicalInterface::setUnits  ,
	  "set the units manager" )
    .def( "setParams", &msPhysicalInterface::setUnits  ,
	  "set the parameters manager" )
    .def(self_ns::str(self_ns::self));
     
    boost::python::scope().attr("pi") = csts::pi; 
    boost::python::scope().attr("hb") = csts::hb; 
    boost::python::scope().attr("kb") = csts::kb; 
    boost::python::scope().attr("h") = csts::h; 
    boost::python::scope().attr("R") = csts::R; 
    boost::python::scope().attr("Nav") = csts::Nav;

    msPhysicalInterface::isInterfaceRegisteredInPython=1;
  }
#endif
 }

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void msPhysicalInterface::setParameters(boost::shared_ptr<msParamsManager> param){

 msTreeMapper::update<msParamsManager>( Parameters , param);
 Parameters->addObjectUsingMe( boost::static_pointer_cast<msPhysicalInterface>( mySharedPtr() ) );
 Parameters->setAffiliation(mySharedPtr());
 updateParameters();
}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
		     
void msPhysicalInterface::setUnits(boost::shared_ptr<msUnitsManager> units){

 msUnitsManager old; 
 old.set( Units->getExpression() );

 msTreeMapper::update<msUnitsManager>( Units , units);
 units->addObjectUsingMe( boost::static_pointer_cast<msPhysicalInterface>( mySharedPtr() ) );

 updateUnits(old,*units); 
}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
 
void msPhysicalInterface::updateUnits(msUnitsManager& Old,msUnitsManager& New) {

 vector< pair< double* , msUnit > >::iterator it = PtrOnPhysicalVariables.begin();

 for(;it!=PtrOnPhysicalVariables.end();++it){

    *((*it).first) *= New.convert( (*it).second, 1 );
    (*it).second.reset(New);
 }
}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void msPhysicalInterface::declarePhysicalVariable(const msUnit& unit,double* ptr) {

 PtrOnPhysicalVariables.push_back( pair<double* , msUnit>(ptr,unit) ); 
}


//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

std::string getStringUnit(strunit::UnitType type, msPhysicalInterface* obj) {
 
 using namespace strunit;  
 switch( type ) {
    case dKinEner:  
       return obj->getUnits()->getMassStr() +"."+ obj->getUnits()->getLengthStr() + "^2"; break ;
    case dP:  
       return obj->getUnits()->getMassStr() +"."+ obj->getUnits()->getLengthStr(); break ;
    case dJ:  
       return obj->getUnits()->getMassStr() +"."+ obj->getUnits()->getLengthStr() + "^2"; break ;
 }
 return "";
}
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

std::ostream& msPhysicalInterface::print(std::ostream& out) const {

 msTreeMapper::print(out);
 output::printHeader(out,"Physical interface");
 out<<"\nParameters: \n";
 Parameters->print(out);
 out<<"\nUnits: \n";
 Units->abstract(out);
 out<<"\n";
 return out;
 }

}
